
from datetime import datetime
from PyQt5 import QtGui
from PyQt5.QtCore import QTime, QTimer
from PyQt5.QtWidgets import QDialog, QFileDialog, QMenu, QMessageBox, QTreeWidgetItem, QWidget
from Trace.toolMsgTraceUi import Ui_Trace
import cantools
import can

class ToolTrace(QWidget,Ui_Trace):

    def __init__(self,parent) -> None:
        
        super(ToolTrace,self).__init__()
        self.parent = parent
        self.setupUi(self)
        self.treeWidgetMsg.setColumnCount(8)
        self.treeWidgetMsg.setHeaderLabels(['Count','TimeStamp','DT','Channel', 'ID','DLC', 'Data','Name'])
        self.dbcFilePath = None
        self.dbcFile = None
        self.logFilePath = None
        self.logFile = None
        self.updateDrawTime = QTimer()
        self.updateDrawTime.start(50)
        self.updateDrawTime.timeout.connect(self.updateDisplayCanMsgOnTrace)
        self.msgCount = 0
        self.canMsgParse = False
        self.ids = {}
        self.root = {}
        self.msgDisplayMethod = 'Expansion'
        
    def loadDbcFile(self,filePath):
        
        self.dbcFile = cantools.database.load_file(filePath)
        self.dbcFilePath = filePath
        self.canMsgParse = True
        
    def loadLogFile(self,filePath):
        self.logFile = can.BLFReader(filePath)

        self.logFilePath = filePath

    def addDisplayCanMsg(self) -> bool:
        
        if self.parent.testerToolMsgSetting.modeSwitch == 'offline' :
            if  self.logFilePath :
                self.logFile = can.BLFReader(self.logFilePath)
                for msg in self.logFile:
                    self.parent.canMsgRecQueue.put(msg)

                return True
            else:
                status =  QMessageBox.warning(self,'blf file','please load blf file',QMessageBox.Yes|QMessageBox.No)
                if status == QMessageBox.Yes:
                    openfile_name = QFileDialog.getOpenFileName(self, 'Load log file', './testLog',filter = 'DbcFile(*.blf)')
                    if openfile_name[0]:
                        self.parent.testerToolMsgSetting.blfLogPathlineEdit.setText(openfile_name[0])
                        self.logFile = can.BLFReader(openfile_name[0])
                        for msg in self.logFile:
                            self.parent.canMsgRecQueue.put(msg)
                else:
                    return False

    def drawCanMessage(self,msg):
        new_id_added, length_changed = False, False
        if(self.msgCount == 0):
            self.startTime = msg.timestamp
        self.msgCount += 1
        arbitration_id_string = '0x{0:0{1}X}'.format(msg.arbitration_id, 8 if msg.is_extended_id else 3)
        data_string = ''
        if msg.dlc > 0:
            data_string = ' '.join('{:02X}'.format(x) for x in msg.data)
            
        if self.msgDisplayMethod == 'Expansion':
            self.rootItme = QTreeWidgetItem(self.treeWidgetMsg)
            self.rootItme.setText(0,str(self.msgCount))
            datatime = datetime.fromtimestamp(msg.timestamp).strftime('%H:%M:%S')
            self.rootItme.setText(1,str(datatime))
            # rootItme.setText(2,str(datatime))
            self.rootItme.setText(3,str(msg.channel))
            self.rootItme.setText(4,arbitration_id_string)
            self.rootItme.setText(5, str(msg.dlc))
            self.rootItme.setText(6, data_string)
        else:
            key = msg.arbitration_id
            if key not in self.ids:
                new_id_added = True
                if not self.start_time:
                    self.start_time = msg.timestamp
                elif msg.dlc != self.ids[key]['msg'].dlc:
                    length_changed = True

                if new_id_added or length_changed:
                    self.root[key] = QTreeWidgetItem(self.tree)
                    self.ids[key] = { 'count': 0, 'msg': msg, 'dt': 0}
                else:
                    self.ids[key]['dt'] = msg.timestamp - self.ids[key]['msg'].timestamp
                    self.ids[key]['msg'] = msg
                    self.root[key].setText(0,str(self.ids[key]['count']))
                    datatime = datetime.fromtimestamp(msg.timestamp).strftime('%H:%M:%S')
                    self.root[key].setText(1, str(datatime))
                    self.root[key].setText(2,'{0:.6f}'.format(self.ids[key]['dt']))
                    self.root[key].setText(3, str(msg.channel))
                    self.root[key].setText(4,arbitration_id_string)
                    self.root[key].setText(5, str(msg.dlc))
                    self.root[key].setText(6, data_string)

        
    def updateDisplayCanMsgOnTrace(self):
        
        if self.parent.testerToolMsgSetting.startSwitch == 'readyStart':
            while not self.parent.canMsgRecQueue.empty():
                msg = self.parent.canMsgRecQueue.get()
                self.drawCanMessage(msg)
                if self.canMsgParse == True:
                   self.parseDbcCanMsg(msg,self.rootItme)
        else:
            # self.updateDrawTime.stop()
            pass
                        
    def parseDbcCanMsg(self,msg,rootItme):
        if msg.arbitration_id in list(self.dbcFile._frame_id_to_message):
            rootItme.setText(7, str(self.dbcFile._frame_id_to_message[msg.arbitration_id].name))
            
    def contextMenuEvent(self, event):
        contextMenuRoot = QMenu(self)
        contextMenuChild = QMenu()
        # Add_signals_Act = contextMenu.addAction("Add Signals  Expansion")
        contextMenuChild.addAction('Expansion')
        contextMenuChild.addAction('Pullback')
        contextMenuChild.setTitle('Messgae')
        contextMenuRoot.addMenu(contextMenuChild)
        contextMenuRoot.triggered.connect(self.contextMenuTriggered)
        action = contextMenuRoot.exec_(self.mapToGlobal(event.pos()))

    
    def contextMenuTriggered(self,action):
        
        self.msgDisplayMethod = action.text()
        
    
    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        # self.close(True)
        self.updateDrawTime.stop()
        return super().closeEvent(a0)